#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <conio.h>
#include <time.h>
#include <allegro5/allegro.h>
#include <allegro5/allegro_image.h>
#include <allegro5/allegro_font.h>
#include <allegro5/allegro_ttf.h>
#include<allegro5/allegro_primitives.h>
#include <vector>
#include "Arena.h"
#include "Questions.h"
#include "HUD.h"
#include "player.h"
#include "robber.h"

using namespace std;

// Function declarations
int initialise_allegro();
void process_events();
 
// Global variables
enum KEYS_PRESSED_LIST
{
   KEY_ESCAPE, KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_SPACE, KEY_M, SIZE_OF_KEYS_PRESSED_ENUM
};

bool keys_pressed[SIZE_OF_KEYS_PRESSED_ENUM];

ALLEGRO_DISPLAY* display = NULL;
ALLEGRO_FONT* dejavusans = NULL;
ALLEGRO_EVENT_QUEUE* event_queue = NULL;

//global variables for keeping the framerate constant
ALLEGRO_EVENT_QUEUE* timer_event_queue = NULL;
ALLEGRO_TIMER* timer = NULL;
int frames_per_second = 60;

bool update_logic = true;
bool render_frame = true;
int consecutive_logic_updates = 0;
int max_consecutive_logic_updates = 10;

bool gameWon = false;
int questionID = 0;

int main()
{
	// initialise everything
	bool init_ok = initialise_allegro();

	if(init_ok!=0) 
	{
		return init_ok; // exit if init failed
	}

	srand(time(NULL));

	Arena* pArena = new Arena();
	HUD* pHUD = new HUD();
	vector<Questions*> pQuestions;
	
	Questions* question1 = new Questions(pArena, "assets/Q1.png", 0, 0);
	pQuestions.push_back( question1 );
	
	Questions* question2 = new Questions(pArena, "assets/Q2.png", 1, 1);
	pQuestions.push_back( question2 );

	Questions* question3 = new Questions(pArena, "assets/Q3.png", 2, 2);
	pQuestions.push_back( question3 );

	Questions* question4 = new Questions(pArena, "assets/Q4.png", 0, 3);
	pQuestions.push_back( question4 );

	Questions* question5 = new Questions(pArena, "assets/Q5.png", 2, 4);
	pQuestions.push_back( question5 );

	Questions* question6 = new Questions(pArena, "assets/Q6.png", 2, 5);
	pQuestions.push_back( question6 );

	Questions* question7 = new Questions(pArena, "assets/Q7.png", 2, 6);
	pQuestions.push_back( question7 );

	Questions* question8 = new Questions(pArena, "assets/Q8.png", 2, 7);
	pQuestions.push_back( question8 );

	Questions* question9 = new Questions(pArena, "assets/Q9.png", 0, 8);
	pQuestions.push_back( question9 );

	Questions* question10 = new Questions(pArena, "assets/Q10.png", 0, 9);
	pQuestions.push_back( question10 );


	for(int i=0 ; i<10 ; i++)
	{
		pQuestions[i]->Spawn();
	}

	player* pPlayer = new player("assets/player_sprite_sheet.png", pArena);
	robber* pRobber = new robber("assets/robber_sprite_sheet.png", pArena);
	pRobber->spawn(pPlayer);

	ALLEGRO_BITMAP* game_won_screen = al_load_bitmap("assets/game_won_screen.png");
	ALLEGRO_BITMAP* game_lost_screen = al_load_bitmap("assets/game_lost_screen.png");

	int frame_counter = 0;
	int player_moved = 0;
	bool question_displayed = false;

	al_start_timer(timer);
	do
	{	
		process_events();
		// --------------------------LOGIC START--------------------------------
		if(update_logic)
		{
			update_logic = false;

			if(keys_pressed[KEY_UP])
			{
				if(question_displayed)
				{
					for(int i=0 ; i<10 ; i++)
						pQuestions[i]->PreviousAnswer();
				}
				else
				{
					pPlayer->up();
					player_moved++;
				}
				keys_pressed[KEY_UP] = false;
			}
			if(keys_pressed[KEY_DOWN])
			{
				if(question_displayed)
				{
					for(int i=0 ; i<10 ; i++)
						pQuestions[i]->NextAnswer();
				}
				else
				{
					pPlayer->down();
					player_moved++;
				}
				keys_pressed[KEY_DOWN] = false;
			}
			if(keys_pressed[KEY_RIGHT])
			{
				if(!question_displayed)
				{
					pPlayer->right();
					player_moved++;
				}
				keys_pressed[KEY_RIGHT] = false;
			}
			if(keys_pressed[KEY_LEFT])
			{
				if(!question_displayed)
				{
					pPlayer->left();
					player_moved++;
				}
				keys_pressed[KEY_LEFT] = false;
			}
			if(keys_pressed[KEY_SPACE])
			{
				if(question_displayed)
				{
					//int i=0;
					//i = pHUD->GetNumberOfQuestionsAnswered();
					if (pQuestions[questionID]->Answered() )
					{
						pHUD->AnsweredaQuestion();
						if(pQuestions[questionID]->IsDevice())
						{
							pHUD->SetDevices(pHUD->GetDevices() + 1);
						}
					}
					else
					{
						pQuestions[questionID]->Spawn();
					}
					question_displayed = false;
				}

				keys_pressed[KEY_SPACE] = false;
			}

			frame_counter++;
			if(frame_counter % 30 == 0)
			{
				for(int i=0 ; i<10 ; i++)
					pQuestions[i]->NextFrame();
				frame_counter = 0;
			}

			for(int i=0 ; i<10 ; i++)
			{
				 if(pQuestions[i]->CollideWithPlayer(pPlayer) )
				{
					questionID = pQuestions[i]->getID();
					question_displayed = true;
					break;
				}
			}

			if(pRobber != NULL)
			{
				if(pRobber->CollidesWithPlayer(pPlayer))
				{
					if(pHUD->GetDevices() > 0)
					{
						pHUD->SetDevices(pHUD->GetDevices() - 1);
						pRobber->spawn(pPlayer);
					}
					else
					{
						keys_pressed[KEY_ESCAPE] = true;
					}
				}
			}
			
			if(pRobber != NULL)
			{
				if(player_moved > 1)
				{
					pRobber->chase(pPlayer);
					player_moved = 0;
				}
			}

			if(pPlayer->DidReachPolice())
			{
				delete pRobber;
				pRobber = NULL;
			}

		}
		// --------------------------LOGIC END--------------------------------

		// --------------------------RENDER START--------------------------------
		if(render_frame)
		{
			render_frame = false;

			pArena->Render();
			pPlayer->render();
			pHUD->Render();
			
			if(pRobber != NULL)
				pRobber->render();

			for(unsigned int i=0 ; i<pQuestions.size() ; i++)
				pQuestions[i]->Render();

			if(question_displayed)
			{	
				pQuestions[questionID]->RenderQuestion();
			}
			al_flip_display();
		}
		// --------------------------RENDER END--------------------------------

	}while(!keys_pressed[KEY_ESCAPE] && pHUD->GetNumberOfQuestionsAnswered() < 10);

	if(pHUD->GetNumberOfQuestionsAnswered() >= 10)
		gameWon = true;

	if(gameWon)
		al_draw_bitmap(game_won_screen, 0,0,0);
	else
		al_draw_bitmap(game_lost_screen,0,0,0);
	al_flip_display();
	al_rest(5.0f);


}

void process_events()
{
	ALLEGRO_EVENT allegro_event;

	// get the next event from the event queue
	bool got_event = al_get_next_event(event_queue, &allegro_event);

	if(got_event == false) return; // no event waiting

	// test if a key is pressed down, update global keypress array
	if(allegro_event.type == ALLEGRO_EVENT_KEY_DOWN) 
	{
		switch(allegro_event.keyboard.keycode) 
		{
		case ALLEGRO_KEY_ESCAPE:
			keys_pressed[KEY_ESCAPE] = true;
			break;
		case ALLEGRO_KEY_UP:
			keys_pressed[KEY_UP] = true;
			break;
		case ALLEGRO_KEY_LEFT:
			keys_pressed[KEY_LEFT] = true;
			break;
		case ALLEGRO_KEY_DOWN:
			keys_pressed[KEY_DOWN] = true;
			break;
		case ALLEGRO_KEY_RIGHT:
			keys_pressed[KEY_RIGHT] = true;
			break;
		case ALLEGRO_KEY_SPACE:
			keys_pressed[KEY_SPACE] = true;
			break;
		case ALLEGRO_KEY_Q:
			keys_pressed[KEY_M] = true;
			break;
		}
	}	
	// Test if a key is let go, update global keypress array
	else if(allegro_event.type == ALLEGRO_EVENT_KEY_UP) 
	{
		switch(allegro_event.keyboard.keycode) 
		{
		case ALLEGRO_KEY_ESCAPE:
			keys_pressed[KEY_ESCAPE] = false;
			break;
		case ALLEGRO_KEY_UP:
			keys_pressed[KEY_UP] = false;
			break;
		case ALLEGRO_KEY_LEFT:
			keys_pressed[KEY_LEFT] = false;
			break;
		case ALLEGRO_KEY_DOWN:
			keys_pressed[KEY_DOWN] = false;
			break;
		case ALLEGRO_KEY_RIGHT:
			keys_pressed[KEY_RIGHT] = false;
			break;
		case ALLEGRO_KEY_SPACE:
			keys_pressed[KEY_SPACE] = false;
			break;
		case ALLEGRO_KEY_M:
			keys_pressed[KEY_M] = false;
			break;
		}
	}
	else if(got_event && allegro_event.type == ALLEGRO_EVENT_TIMER)
	{
		// if logic taking too long ensures frame is rendered occasionally and input is responsive
		// this essentially ignores logic updates if there are a lot of consecutive ones

		if(++consecutive_logic_updates < max_consecutive_logic_updates)
		{
			update_logic = true;
		}

		// only render frame if no events left to process
		if(al_is_event_queue_empty(event_queue))
		{
			render_frame = true;
			consecutive_logic_updates=0;
		}
	}
}

int initialise_allegro()
{
	if(!al_init()) 
	{
		cout << "Allegro initialisation failed" << endl;
		cout << "Press any key to exit" << endl;
		_getch();
		return -1;
	}

	if(!al_init_image_addon())
	{
		cout << "Allegro image initialisation failed" << endl;
		cout << "Press any key to exit" << endl;
		_getch();
		return -1;
	}

	al_init_primitives_addon();

	// tell allegro program needs keyboard input
	if(!al_install_keyboard()) 
	{
		cout << "Keyboard initialisation failed" << endl;
		cout << "Press any key to exit" << endl;
		_getch();
		return -1;
	}

	// initialise keypress array
	for(int i=0; i < SIZE_OF_KEYS_PRESSED_ENUM; i++) 
	{
		keys_pressed[i] = false;
	}

	display = al_create_display(800, 600); // create a display window of size 640 by 480

	if(!display) 
	{
		cout << "Display initialisation failed" << endl;
		cout << "Press any key to exit" << endl;
		_getch();
		return -1;
	}

 	al_set_window_position(display, 250, 50); // position display window on screen

	//initializing font and TTFont addons, loading DejaVuSans into a global variable
	al_init_font_addon();
   	al_init_ttf_addon();
	dejavusans = al_load_ttf_font("assets/DejaVuSans.ttf", 15, 0);
	if(!dejavusans)
	{
		cout << "Big Font creation failed" << endl;
		cout << "Press any key to exit" << endl;
		_getch();
		al_destroy_font(dejavusans);
		al_destroy_display(display);
		return -1;	
	}

	// need to create an event queue so allegro can respond to events, such as keypresses
	event_queue = al_create_event_queue();

	if(!event_queue) 
	{
		cout << "Event queue creation failed" << endl;
		cout << "Press any key to exit" << endl;
		_getch();
		al_destroy_display(display);
		return -1;
	}
 
	timer = al_create_timer(1.0 / frames_per_second);

	// register  display with the event queue, so display change events can be processed
	al_register_event_source(event_queue, al_get_display_event_source(display));

	// register keyboard with the event queue, so keypress events can be processed
	al_register_event_source(event_queue, al_get_keyboard_event_source());

	// register timer with the event queue, to help keep framerate constant
	al_register_event_source(event_queue, al_get_timer_event_source(timer));

	return 0;
}